use calamine::{Reader,Xlsx};
use std::path::Path;
use std::collections::HashSet;


enum ReadXlsErr
{
    OpenXlsFailed,
    XlsNoSheets,
    ReadSheetErr,
}

impl ReadXlsErr
{
    fn msg(&self)->String
    {
        match self
        {
            Self::OpenXlsFailed=>
            {
                return String::from("open xls file failed.");
            }
            Self::XlsNoSheets=>
            {
                return String::from("xls file have no sheets.");
            }
            Self::ReadSheetErr=>
            {
                return String::from("read sheet failed.");
            }
            _=>
            {
                return String::from("unknown err.");
            }
        }
    }
}



fn read_sheet_data(path:&str)->Result<Vec<String>,ReadXlsErr>
{
    let mut datas:Vec<String> = Vec::new();
    let mut workbook;
    if let Ok(v) = calamine::open_workbook::<Xlsx<_>,_>(path)
    {
        workbook = v;
    }
    else 
    {
        return Err(ReadXlsErr::OpenXlsFailed);
    }


    // println!("{:?}",workbook.sheet_names());

    if workbook.sheet_names().is_empty()
    {
        return Err(ReadXlsErr::XlsNoSheets);
    }

    let sheet = &workbook.sheet_names()[0];
    if let Ok(range) = workbook.worksheet_range(sheet)
    {
        for row in range.rows()
        {
            if let Some(v) = row.first()
            {
                datas.push(v.to_string());
            }
        }
    }
    else 
    {
        return Err(ReadXlsErr::ReadSheetErr);
    }


    return Ok(datas);
}


fn main() {
    let mut args:Vec<String> = std::env::args().collect();
    if args.len() == 1
    {
        args.push(String::from("/home/xx/data/a.xlsx"));
        args.push(String::from("/home/xx/data/b.xlsx"));
    }
    if args.len() != 3
    {
        println!("please input two excel files.");
        return;
    }
    let patha = Path::new(&args[1]);
    if !patha.exists()
    {
        println!("{} is not existed.",&args[1]);
        return;
    }
    let pathb = Path::new(&args[2]);
    if !pathb.exists()
    {
        println!("{} is not existed.",&args[2]);
        return;
    }
    let res_a = read_sheet_data(&args[1]);

    let data_a;
    match res_a
    {
        Ok(v)=>
        {
            data_a = v.into_iter().collect::<HashSet<_>>();
        }
        Err(e)=>
        {
            println!("read {} err, {}",&args[1],e.msg());
            return;
        }
    }

    // println!("{:?}",data_a);

    let res_b = read_sheet_data(&args[2]);
    let data_b;
    match res_b
    {
        Ok(v)=>
        {
            data_b = v.into_iter().collect::<HashSet<_>>();
        }
        Err(e)=>
        {
            println!("read {} err, {}",&args[2],e.msg());
            return;
        }
    }
    // println!("{:?}",data_b);

    let common = &data_a & &data_b;
    let only_a = &data_a - &data_b;
    let only_b = &data_b - &data_a;

    println!("- {:?}",only_a);
    println!("= {:?}",common);
    println!("+ {:?}",only_b);
}
